package com.seed.uaa.web.organization;

import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.seed.application.service.BaseService;
import com.seed.core.enumeration.YesNo;
import com.seed.core.pojo.Const;
import com.seed.core.pojo.Node;
import com.seed.core.pojo.SetDTO;
import com.seed.util.StrKit;
import com.seed.uaa.pojo.OrganizationAction;
import com.seed.uaa.pojo.OwnerAction;
import com.seed.uaa.pojo.RoleAction;
import com.seed.uaa.util.PermiUtil;
import com.seed.uaa.web.UaaService;
import com.seed.uaa.web.role.Role;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

import static com.seed.uaa.web.organization.table.OrganizationRoleTableDef.ORGANIZATION_ROLE;
import static com.seed.uaa.web.organization.table.OrganizationTableDef.ORGANIZATION;
import static com.seed.uaa.web.role.table.RoleTableDef.ROLE;

@Service
public class OrganizationService extends BaseService<OrganizationMapper, Organization> {

    private final UaaService uaaService;

    public OrganizationService(@Lazy UaaService uaaService) {
        super(Organization.class);
        this.uaaService = uaaService;
    }

    @Override
    @Transactional
    public boolean save(Organization organization) {
        String newCode = organization.getCode();
        List<Organization> organizations = list(query().where(ORGANIZATION.CODE.eq(newCode)));
        if(!organizations.isEmpty()) {
            throw new RuntimeException(String.format("编码【%s】已存在", newCode));
        }

        String[] items = StrKit.cutInTwo(newCode, Const.CODE_SEPARATOR, true);
        String parentCode = items[0];
        if(StrUtil.isNotBlank(parentCode)) {
            Organization parent = getMapper().selectOneByQuery(query().where(ORGANIZATION.CODE.eq(parentCode)));
            if(parent == null) throw new RuntimeException(String.format("父组织【%s】不存在", parentCode));

            Integer clerkSize = parent.getClerkSize();
            if(clerkSize != null) {
                QueryWrapper qw = query()
                        .select(QueryMethods.count())
                        .where(ORGANIZATION.CODE.likeLeft(parentCode + Const.CODE_SEPARATOR));
                Long count = (Long) getMapper().selectObjectByQuery(qw);
                if(clerkSize < count + 1) throw new RuntimeException(String.format("【%s】的编制已满", parent.getName()));
            }
        }

        organization.setUsable(YesNo.yes);
        organization.setLoginable(YesNo.yes);
        organization.setEnable(YesNo.yes);
        return super.save(organization);
    }

    public List<Node<Organization>> tree(boolean containLeaf) {
        QueryWrapper qw = query();
        if(!containLeaf) qw.where(ORGANIZATION.CLERK_SIZE.isNull()).or(ORGANIZATION.CLERK_SIZE.ne(0));

        List<Organization> organizations = list(qw);
        List<Node<Organization>> roots = organizations.stream()
                .filter(e -> e.getParentId() == null)
                .map(e -> {
                    Node<Organization> node = new Node<>(e.getId(), e.getName());
                    node.setData(e);
                    return node;
                }).toList();
        fillChildren(roots, organizations);

        return roots;
    }

//    @Transactional
//    public boolean setCode(SetDTO dto) {
//        String id = dto.getId();
//        String value = dto.getValue();
//        if(StrUtil.isBlank(value)) throw new RuntimeException("编码不能为空");
//        if(value.contains(String.valueOf(Const.CODE_SEPARATOR))) throw new RuntimeException("编码不能包含点分隔符");
//
//        Organization exist = getById(id);
//        if(exist == null) throw new RuntimeException("数据不存在");
//
//        String oldCode = exist.getCode();
//        String[] items = StrKit.cutInTwo(oldCode, Const.CODE_SEPARATOR, true);
//        String parentCode = items[0];
//        String selfCode = items[1];
//        if(selfCode.equals(value)) return true;
//
//        String newCode = StrUtil.isBlank(parentCode) ? value : parentCode + Const.CODE_SEPARATOR + value;
//        List<Organization> organizations = list(query().where(ORGANIZATION.CODE.eq(newCode)).and(ORGANIZATION.ID.ne(id)));
//        if(organizations.isEmpty()) {
//            List<Organization> children = list(query().where(ORGANIZATION.CODE.likeLeft(oldCode + Const.CODE_SEPARATOR)));
//            for(Organization child: children) {
//                String newChildCode = newCode + Const.CODE_SEPARATOR + child.getCode().substring(newCode.length() + 1);
//                UpdateChain.of(Organization.class)
//                        .set(Organization::getCode, newChildCode)
//                        .where(ORGANIZATION.ID.eq(child.getId()))
//                        .update();
//            }
//
//            return UpdateChain.of(Organization.class)
//                    .set(Organization::getCode, newCode)
//                    .where(ORGANIZATION.ID.eq(id))
//                    .update();
//        }
//
//        throw new RuntimeException(String.format("编码【%s】已存在", newCode));
//    }

    public boolean setClerkSize(SetDTO dto) {
        String id = dto.getId();
        Integer value = StrUtil.isBlank(dto.getValue()) ? null : Integer.parseInt(dto.getValue());
        Organization exist = getById(id);
        if(exist == null) throw new RuntimeException("数据不存在");
        if(value != null) {
            QueryWrapper qw = query()
                    .select(QueryMethods.count())
                    .where(ORGANIZATION.CODE.likeLeft(exist.getCode() + Const.CODE_SEPARATOR));
            Long count = (Long) getMapper().selectObjectByQuery(qw);
            if(value < count) {
                throw new RuntimeException(String.format("已存在【%s】个后代组织，请填写大于或等于【%s】的值或删除一些后代组织", count, count));
            }
        }
        return UpdateChain.of(Organization.class)
                .set(Organization::getClerkSize, value)
                .where(ORGANIZATION.ID.eq(id))
                .update();
    }

//    public OwnerAction getOwnerAction(String id) {
//        return uaaService.getOwnerAction(PermiOwner.organization, id);
//    }

    public OwnerAction getOwnerAction(String id) {
        Organization organization = getById(id);
        if(organization == null) throw new RuntimeException("数据不存在");

        String actionPermis = organization.getActions();
        System.out.println("actionPermis===============");
        System.out.println(actionPermis);
        return null;
    }

    public boolean setActions(SetDTO dto) {
        String id = dto.getId();
        Organization organization = one(id);
        if(organization == null) throw new RuntimeException("数据不存在");

        String value = dto.getValue();
        organization.setActions(value);
        return getMapper().update(organization) > 0;
    }

    @Transactional
    public boolean setDatas(String id, String actionPath, List<String> params) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.DATAS, ORGANIZATION.VERSION)
                .where(ORGANIZATION.ID.eq(id));

        Organization organization = getMapper().selectOneByQuery(queryWrapper);
        if(organization == null) throw new RuntimeException("数据不存在");

        organization.setDatas(PermiUtil.edit(organization.getDatas(), actionPath, params));
        return getMapper().update(organization) > 0;
    }

    public boolean setFields(String id, String actionPath, Map<String, String> params) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.FIELDS, ORGANIZATION.VERSION)
                .where(ORGANIZATION.ID.eq(id));

        Organization organization = getMapper().selectOneByQuery(queryWrapper);
        if(organization == null) throw new RuntimeException("数据不存在");

        organization.setFields(PermiUtil.edit(organization.getFields(), actionPath, params));
        return getMapper().update(organization) > 0;
    }

    private Organization one(String id) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.VERSION)
                .where(ORGANIZATION.ID.eq(id));
        return getMapper().selectOneByQuery(queryWrapper);
    }

    /**
     * 我自己的权限
     */
    public List<String> getActions(String id) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.ACTIONS)
                .where(ORGANIZATION.ID.eq(id));

        Organization organization = getMapper().selectOneByQuery(queryWrapper);
        if(organization == null) throw new RuntimeException("数据不存在");

        String actions = organization.getActions();
        if(StrUtil.isBlank(actions)) return Collections.emptyList();

        return List.of(actions.split(","));
    }

    /**
     * 我拥有的权限，包含我自己的权限和角色的权限，用or连接
     */
    public List<String> getHaveActions(String id) {
        List<String> ret = new ArrayList<>(getActions(id));
//        List<Object> roleIds = QueryChain.of(OrganizationRole.class)
//                .select(ORGANIZATION_ROLE.ROLE_ID)
//                .where(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
//                .objList();
//        List<Role> roles = QueryChain.of(Role.class)
//                .select(ROLE.ID, ROLE.ACTIONS)
//                .where(ROLE.ID.in(roleIds))
//                .list();

        List<Role> roles = QueryChain.of(Role.class)
            .select(ROLE.ID, ROLE.ACTIONS)
            .innerJoin(ORGANIZATION_ROLE).on(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
            .list();
        for(Role role: roles) {
            String actions = role.getActions();
            if(StrUtil.isNotBlank(actions)) {
                ret.addAll(List.of(actions.split(",")));
            }
        }

        return ret.stream().distinct().toList();
    }

    // 我最终的权限，等于我拥有的权限
    public List<String> getFinalActions(String id) {
        return getHaveActions(id);
    }

    /**
     * 我自己的权限, 如
     * micro.action:column_op=1
     * micro.seed.action:column_op=1
     * @param id 组织ID
     * @param actionPath 形如：micro.seed.action
     * @return 列表
     */
    public List<String> getDatas(String id, String actionPath) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.DATAS)
                .where(ORGANIZATION.ID.eq(id));

        Organization organization = getMapper().selectOneByQuery(queryWrapper);
        if(organization == null) throw new RuntimeException("数据不存在");

        String datas = organization.getDatas();
        if(StrUtil.isBlank(datas)) return Collections.emptyList();

        return PermiUtil.extract(datas, actionPath);
    }

    /**
     * 我拥有的权限：包含我自己的权限和角色的权限, 用or连接
     */
    public List<List<String>> getHaveDatas(String id, String actionPath) {
        List<String> selfDatas = getDatas(id, actionPath);
//        List<Object> roleIds = QueryChain.of(OrganizationRole.class)
//                .select(ORGANIZATION_ROLE.ROLE_ID)
//                .where(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
//                .objList();
//        List<Role> roleList = QueryChain.of(Role.class)
//                .select(ROLE.ID, ROLE.DATAS)
//                .where(ROLE.ID.in(roleIds))
//                .list();
        List<Role> roles = QueryChain.of(Role.class)
            .select(ROLE.ID, ROLE.DATAS)
            .innerJoin(ORGANIZATION_ROLE).on(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
            .list();

        List<List<String>> ret = new ArrayList<>();
        ret.add(selfDatas);
        for(Role role: roles) {
            String datas = role.getDatas();
            if(StrUtil.isNotBlank(datas)) {
                ret.add(PermiUtil.extract(datas, actionPath));
            }
        }

        return ret;
    }

    /**
     * 我自己的权限, 如
     * micro.action:column=~加1
     * micro.seed.action:column=~翻倍
     * @param id 组织ID
     * @param actionPath 形如：micro.seed.action
     * @return 列表
     */
    public Map<String, String> getFields(String id, String actionPath) {
        QueryWrapper queryWrapper = query()
                .select(ORGANIZATION.ID, ORGANIZATION.FIELDS)
                .where(ORGANIZATION.ID.eq(id));

        Organization organization = getMapper().selectOneByQuery(queryWrapper);
        if(organization == null) throw new RuntimeException("数据不存在");

        String fields = organization.getFields();
        if(StrUtil.isBlank(fields)) return Collections.emptyMap();

        Map<String, String> ret = new HashMap<>();
        PermiUtil.fillFields(ret, fields, actionPath);

        return ret;
    }

    /**
     * 我拥有的权限：包含我自己的权限和角色的权限, 用or连接
     */
    public Map<String, String> getHaveFields(String id, String actionPath) {
        Map<String, String> ret = getFields(id, actionPath);
//        List<Object> roleIds = QueryChain.of(OrganizationRole.class)
//                .select(ORGANIZATION_ROLE.ROLE_ID)
//                .where(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
//                .objList();
//        List<Role> roleList = QueryChain.of(Role.class)
//                .select(ROLE.ID, ROLE.FIELDS)
//                .where(ROLE.ID.in(roleIds))
//                .list();
        List<Role> roles = QueryChain.of(Role.class)
            .select(ROLE.ID, ROLE.FIELDS)
            .innerJoin(ORGANIZATION_ROLE).on(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
            .list();

        for(Role role: roles) {
            String fields = role.getFields();
            if(StrUtil.isBlank(fields)) {
                PermiUtil.fillFields(ret, fields, actionPath);
            }
        }

        return ret;
    }

    public OrganizationAction getOrganizationAction(String id) {
        Organization organization = QueryChain.of(Organization.class)
                .select(ORGANIZATION.ID, ORGANIZATION.NAME, ORGANIZATION.ACTIONS)
                .where(ORGANIZATION.ID.eq(id))
                .one();
        if(organization == null) throw new RuntimeException("数据不存在");

        OrganizationAction ret = new OrganizationAction(organization.getId(), organization.getName());
        String actions = organization.getActions();
        if(StrUtil.isNotBlank(actions)) {
            ret.setActions(List.of(actions.split(",")));
        }

        List<RoleAction> roleActions = new ArrayList<>();
        List<Role> roles = QueryChain.of(Role.class)
                .select(ROLE.ID, ROLE.NAME)
                .innerJoin(ORGANIZATION_ROLE).on(ORGANIZATION_ROLE.ORGANIZATION_ID.eq(id))
                .list();

        for(Role role: roles) {
            RoleAction roleAction = new RoleAction(role.getId(), role.getName());
            String actions1 = role.getActions();
            if(StrUtil.isNotBlank(actions1)) {
                roleAction.setActions(List.of(actions1.split(",")));
                roleActions.add(roleAction);
            }
        }
        ret.setRoleActions(roleActions);

        return ret;
    }

    private void fillChildren(List<Node<Organization>> roots, List<Organization> organizations) {
        for(Node<Organization> root: roots) {
            String id = root.getValue();
            List<Node<Organization>> children = new ArrayList<>();
            for(Organization organization: organizations) {
                String parentId = organization.getParentId();
                if(parentId == null) continue;

                if(id.equals(parentId)) {
                    Node<Organization> node = new Node<>(organization.getId(), organization.getName());
                    node.setData(organization);
                    children.add(node);
                }
            }

            if(!children.isEmpty()) {
                root.setChildren(children);
                fillChildren(children, organizations);
            }
        }
    }
}
